﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Telerik.Windows.Controls;
using System.Collections.ObjectModel;
using TotalSystems.Core.Infrastructure;
using System.ServiceModel.DomainServices.Client;
using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using System.Windows.Data;
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;
using TotalSystems.Core.Converters;
using GalaSoft.MvvmLight.Command;

namespace TotalSystems.Core.Controls
{
    public partial class BaseDefenitionsTreeView : UserControl
    {
        private ObservableCollection<RadTreeViewItem> _tvItems;
        private BaseDefenitionTreeViewBuilder<Entity> _bsBuilder;
        private Type _entityType;
        private bool _isFirstAddedNodeSelected;
        private TreeViewMode _treeviewMode;
        private bool _isMainCollectionChangedRegistered;

        bool _isChildRemoving;
        
        RemoveItems _removeItems;
        BackgroundWorker bw;

        #region Properties

        public NodeMode NodeMode
        {
            get { return (NodeMode)GetValue(NodeModeProperty); }
            set { SetValue(NodeModeProperty, value); }
        }

        public string IDPropertyName { get; set; }

        public string NamePropertyName { get; set; }

        public string ParentIdPropertyName { get; set; }

        public string IsExpandedPropertyName { get; set; }

        public string IsActivePropertyName { get; set; }

        public string ModifyDatePropertyName { get; set; }

        public string DeleteDatePropertyName { get; set; }

        private ObservableCollection<RadTreeViewItem> TVItems
        {
            get { return _tvItems; }
            set { if (_tvItems != value) { _tvItems = value; if (value != null && radTreeView1 != null) { radTreeView1.ItemsSource = value; };} }
        }

        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public object SelectedItem
        {
            get { return GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }

        internal object SelectedItemCopy
        {
            get { return GetValue(SelectedItemCopyProperty); }
            set { SetValue(SelectedItemCopyProperty, value); }
        }

        public bool CanSelectedNodeBeDeleted
        {
            get { return (bool)GetValue(CanSelectedNodeBeDeletedProperty); }
            set { SetValue(CanSelectedNodeBeDeletedProperty, value); }
        }

        public bool CanSelectedNodeBeEdited
        {
            get { return (bool)GetValue(CanSelectedNodeBeEditedProperty); }
            set { SetValue(CanSelectedNodeBeEditedProperty, value); }
        }

        public bool CanAddToSelectedNode
        {
            get { return (bool)GetValue(CanAddToSelectedNodeProperty); }
            set { SetValue(CanAddToSelectedNodeProperty, value); }
        }

        public bool IsReadOnly
        {
            get { return (bool)GetValue(IsReadOnlyProperty); }
            set { SetValue(IsReadOnlyProperty, value); }
        }

        public IList UserAddedNodes
        {
            get { return (IList)GetValue(UserAddedNodesProperty); }
            set { SetValue(UserAddedNodesProperty, value); }
        }

        public IList UserRemovedNodes
        {
            get { return (IList)GetValue(UserRemovedNodesProperty); }
            set { SetValue(UserRemovedNodesProperty, value); }
        }

        public IList UserEditedNodes
        {
            get { return (IList)GetValue(UserEditedNodesProperty); }
            set { SetValue(UserEditedNodesProperty, value); }
        }

        internal TreeViewMode Mode
        {
            get { return _treeviewMode; }
            set { _treeviewMode = value; RefreshCommands(); }
        }

        private List<RadTreeViewItem> TmpAddedNodes { get; set; }

        public ObservableCollection<NodModeWrapper> NodeModes
        {
            get
            {
                return new ObservableCollection<NodModeWrapper> 
                { 
                    new NodModeWrapper{NodeMode=NodeMode.Active,NodeModeName="فعال"},
                    new NodModeWrapper{NodeMode=NodeMode.Inactive,NodeModeName="غیر فعال"},
                    new NodModeWrapper{NodeMode=NodeMode.Both,NodeModeName="هردو"}
                };
            }
        }

        public DataTemplate ItemsTemplate
        {
            get { return (DataTemplate)GetValue(ItemsTemplateProperty); }
            set { SetValue(ItemsTemplateProperty, value); }
        }

        public DataTemplate EditItemsTemplate
        {
            get { return (DataTemplate)GetValue(EditItemsTemplateProperty); }
            set { SetValue(EditItemsTemplateProperty, value); }
        }


        private bool _autoGenerateFields = true;
        [DefaultValue(true)]
        public bool AutoGenerateFields
        {
            get { return _autoGenerateFields; }
            set { _autoGenerateFields = value; RefreshContentVisibility(); }
        }
        #endregion

        #region Dependency Properties Registerations

        public static DependencyProperty EditItemsTemplateProperty = DependencyProperty.Register("EditItemsTemplate",
            typeof(DataTemplate), typeof(BaseDefenitionsTreeView), new PropertyMetadata(null, EditItemsTemplatePropertyChanged));

        public static DependencyProperty ItemsTemplateProperty = DependencyProperty.Register("ItemsTemplate",
            typeof(DataTemplate), typeof(BaseDefenitionsTreeView), new PropertyMetadata(null, ItemsTemplatePropertyChanged));

        private static void ItemsTemplatePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdtv = sender as BaseDefenitionsTreeView;
            if (!bdtv.AutoGenerateFields && e.NewValue != null)
            {
                bdtv.cp1.Content = bdtv.ItemsTemplate.LoadContent();
            }
        }

        private static void EditItemsTemplatePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdtv = sender as BaseDefenitionsTreeView;
            if (!bdtv.AutoGenerateFields && e.NewValue != null && bdtv.Mode != TreeViewMode.View)
            {
                bdtv.cp1.Content = bdtv.EditItemsTemplate.LoadContent();
               // var childControls = bdtv.GetControls(bdtv.cp1);
                //foreach (var ctrl in childControls)
                //{
                //    //var bindingEx = ctrl.GetBindingExpression(
                //}
            }
        }

        private IEnumerable<Control> GetControls(DependencyObject container)
        {
            var controlList = new List<Control>();
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(container); i++)
            {
                DependencyObject ctrl = VisualTreeHelper.GetChild(container,i);
                if (ctrl is Control)
                    controlList.Add(ctrl as Control);
                controlList.AddRange(GetControls(ctrl));
            }
            return controlList;
        }

        public static DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(BaseDefenitionsTreeView), new PropertyMetadata(null, ItemsSourcePropertyChanged));

        public static DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(BaseDefenitionsTreeView), new PropertyMetadata(null, SelectedItemPropertyChanged));

        internal static DependencyProperty SelectedItemCopyProperty = DependencyProperty.Register("SelectedItemCopy", typeof(object), typeof(BaseDefenitionsTreeView), new PropertyMetadata(null, SelectedItemCopyPropertyChanged));

        private static void SelectedItemPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdTV = sender as BaseDefenitionsTreeView;
            //bdTV.SelectedItemCopy = bdTV.SelectedItem;
            //if (bdTV.Mode != TreeViewMode.View)
            //    bdTV.SelectedItemCopy = bdTV.SelectedItem.Clone();

            bdTV.RefreshCommands();
            if (e.NewValue != null && e.NewValue is Entity)
            {

                var selectedItem = bdTV._bsBuilder.FindChidNode<Entity>(bdTV.TVItems, ((Entity)e.NewValue).GetDecimalValue(bdTV.IDPropertyName));
                if (selectedItem != bdTV.radTreeView1.SelectedItem)
                    bdTV.radTreeView1.SelectedItem = selectedItem;
            }
        }

        private static void SelectedItemCopyPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdTV = sender as BaseDefenitionsTreeView;
            bdTV.RefreshCommands();
            //bdTV.RefreshCommands();
            //if (e.NewValue != null && e.NewValue is Entity)
            //{

            //    var selectedItem = bdTV._bsBuilder.FindChidNode<Entity>(bdTV.TVItems, ((Entity)e.NewValue).GetDecimalValue(bdTV.IDPropertyName));
            //    if (selectedItem != bdTV.radTreeView1.SelectedItem)
            //        bdTV.radTreeView1.SelectedItem = selectedItem;
            //}
        }

        private static void ItemsSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdTV = sender as BaseDefenitionsTreeView;
            if (e.NewValue != null)
            {
                Type[] interfaces = bdTV.ItemsSource.GetType().GetInterfaces();
                foreach (Type i in interfaces)
                    if (i.IsGenericType && i.GetGenericTypeDefinition().Equals(typeof(IEnumerable<>)))
                        bdTV._entityType = i.GetGenericArguments()[0];
                if (bdTV.AutoGenerateFields)
                    bdTV.BuildViewElements();
                bdTV.BuildTreeView();
            }
        }

        public static DependencyProperty CanSelectedNodeBeDeletedProperty = DependencyProperty.Register("CanSelectedNodeBeDeleted",
            typeof(bool), typeof(BaseDefenitionsTreeView), new PropertyMetadata(true));

        public static DependencyProperty CanSelectedNodeBeEditedProperty = DependencyProperty.Register("CanSelectedNodeBeEdited",
            typeof(bool), typeof(BaseDefenitionsTreeView), new PropertyMetadata(true, CanSelectedNodeBeEditedPropertyChanged));

        public static DependencyProperty CanAddToSelectedNodeProperty = DependencyProperty.Register("CanAddToSelectedNode",
            typeof(bool), typeof(BaseDefenitionsTreeView), new PropertyMetadata(true, CanAddToSelectedNodePropertyChanged));

        public static void CanSelectedNodeBeDeletedPropertyChanged(DependencyObject sender,DependencyPropertyChangedEventArgs e)
        {
            var bdtv = sender as BaseDefenitionsTreeView;
            bdtv.RefreshCommands();
        }

        public static void CanSelectedNodeBeEditedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdtv = sender as BaseDefenitionsTreeView;
            bdtv.RefreshCommands();
        }

        public static void CanAddToSelectedNodePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdtv = sender as BaseDefenitionsTreeView;
            bdtv.RefreshCommands();
        }

        public static DependencyProperty UserAddedNodesProperty = DependencyProperty.Register("UserAddedNodes",
            typeof(IList), typeof(BaseDefenitionsTreeView), new PropertyMetadata(null, UserAddedNodesPropertyChanged));

        public static DependencyProperty UserRemovedNodesProperty = DependencyProperty.Register("UserRemovedNodes",
            typeof(IList), typeof(BaseDefenitionsTreeView), new PropertyMetadata(null, UserRemovedNodesPropertyChanged));

        public static DependencyProperty UserEditedNodesProperty = DependencyProperty.Register("UserEditedNodes",
            typeof(IList), typeof(BaseDefenitionsTreeView), new PropertyMetadata(null, UserEditedNodesPropertyChanged));

        private static void UserAddedNodesPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        { }

        private static void UserRemovedNodesPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        { }

        private static void UserEditedNodesPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        { }

        public static DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly",
            typeof(bool), typeof(BaseDefenitionsTreeView), new PropertyMetadata(false, OnIsReadOnlyPropertyChanged));

        private static void OnIsReadOnlyPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdtv = sender as BaseDefenitionsTreeView;
            bdtv.RefreshCommands();
        }

        public static DependencyProperty NodeModeProperty = DependencyProperty.Register("NodeMode",
            typeof(NodeMode), typeof(BaseDefenitionsTreeView), new PropertyMetadata(NodeModePropertyChanged));

        private static void NodeModePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var bdtv = sender as BaseDefenitionsTreeView;
            ((RelayCommand)bdtv.AddNode).RaiseCanExecuteChanged();
            bdtv.BuildTreeView(true);
        }
        #endregion

        #region Commands

        public ICommand AddNode { get; set; }

        public ICommand DeleteNode { get; set; }

        public ICommand EditNode { get; set; }

        public ICommand CommitChanges { get; set; }

        public ICommand Cancel { get; set; }
        #endregion

        public BaseDefenitionsTreeView()
        {
            InitializeComponent();
            
            radTreeView1.Selected += new EventHandler<Telerik.Windows.RadRoutedEventArgs>(radTreeView1_Selected);
            
            if (!DesignerProperties.IsInDesignTool)
            {
                _bsBuilder = new BaseDefenitionTreeViewBuilder<Entity>();
                bw = new BackgroundWorker();
                //bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                _removeItems = new RemoveItems(RemoveChildItems);
                radTreeView1.Items.Clear();
                
                AddNode = new RelayCommand(OnAddNodeCommand, CanAddNodeCommandExecute );
                DeleteNode = new RelayCommand(OnDeleteNodeCommand, () => SelectedItem != null && CanSelectedNodeBeDeleted && Mode == TreeViewMode.View ? true : false);
                EditNode = new RelayCommand(OnEditNodeCommand, CanEditNodeCommandExecute);
                Cancel = new RelayCommand(OnCancelCommand, () => Mode != TreeViewMode.View ? true : false);
                CommitChanges = new RelayCommand(OnCommitChangesCommand, () => Mode != TreeViewMode.View ? true : false);

            }
        }

        #region Methods

        private bool CanAddNodeCommandExecute()
        {
            if (AutoGenerateFields)
                return (SelectedItem != null && CanAddToSelectedNode && Mode == TreeViewMode.View && NodeMode != Infrastructure.NodeMode.Inactive) || (TVItems == null || TVItems.Count == 0) ? true : false;
            else
                return (EditItemsTemplate != null && SelectedItemCopy != null && CanAddToSelectedNode && Mode == TreeViewMode.View && NodeMode != Infrastructure.NodeMode.Inactive) || (TVItems == null || TVItems.Count == 0) ? true : false;
        }

        private bool CanEditNodeCommandExecute()
        {
            if (AutoGenerateFields)
                return SelectedItem != null && CanSelectedNodeBeEdited && Mode == TreeViewMode.View ? true : false;
            else
                return EditItemsTemplate != null && SelectedItemCopy != null && CanSelectedNodeBeEdited && Mode == TreeViewMode.View ? true : false;
        }

        private void RefreshContentVisibility()
        {
            if (!AutoGenerateFields)
            {
                //SelectedItemCopy = SelectedItem;
                gridItemsTemplate.Visibility = System.Windows.Visibility.Visible;
                gridEditElements.Visibility = System.Windows.Visibility.Collapsed;
            }
            else
            {
                gridEditElements.Visibility = System.Windows.Visibility.Visible;
                gridItemsTemplate.Visibility = System.Windows.Visibility.Collapsed;
            }
        }

        private void BuildViewElements()
        {
            var propertyInfos = _entityType.GetProperties();
            int gridRowIndex = 0;
            foreach (var pi in propertyInfos)
            {
                var customAttributes = pi.GetCustomAttributes(false);
                if (customAttributes.FirstOrDefault(p => p.GetType() == typeof(DataMemberAttribute)) != null)
                {
                    DisplayAttribute display = customAttributes.FirstOrDefault(p => p.GetType() == typeof(DisplayAttribute)) as DisplayAttribute;
                    StringLengthAttribute length = customAttributes.FirstOrDefault(p => p.GetType() == typeof(StringLengthAttribute)) as StringLengthAttribute;
                    ReadOnlyAttribute readOnly = customAttributes.FirstOrDefault(p => p.GetType() == typeof(ReadOnlyAttribute)) as ReadOnlyAttribute;
                    if ((pi.PropertyType == typeof(string) || pi.PropertyType == typeof(short) || pi.PropertyType == typeof(int)
                        || pi.PropertyType == typeof(long) || pi.PropertyType == typeof(decimal)) && (display == null || display.GetAutoGenerateField() != false))
                    {

                        var tbx = new TextBox();
                        var tb = new TextBlock();
                        //var grid = new Grid();
                        //grid.Width = 300;
                        //grid.Height = 26;
                        //grid.Children.Add(tb);
                        //grid.Children.Add(tbx);
                        //tbx.Width = 100;
                        tbx.IsReadOnly = true;
                        tbx.Height = 23;

                        tbx.Margin = new Thickness(5, 0, 2, 0);
                        tbx.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
                        tbx.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                        tb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                        tb.Width = 130;
                        tb.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                        Binding binding = new Binding
                        {
                            Path = new PropertyPath(pi.Name),
                            Mode = BindingMode.TwoWay,
                            UpdateSourceTrigger = UpdateSourceTrigger.Explicit
                        };

                        if (display != null)
                            tb.Text = display.Name;
                        else
                            tb.Text = pi.Name;
                        //if (length != null)
                        //    tbx.Width = length.MaximumLength * 1.5;

                        if (readOnly != null)
                        {
                            //tbx.IsReadOnly = readOnly.IsReadOnly;
                            tbx.Tag = readOnly.IsReadOnly;
                        }
                        tbx.SetBinding(TextBox.TextProperty, binding);
                        gridEditElements.RowDefinitions.Add(new RowDefinition { Height = new GridLength(25) });
                        gridEditElements.Children.Add(tb);
                        gridEditElements.Children.Add(tbx);
                        tb.SetValue(Grid.RowProperty, gridRowIndex);
                        tbx.SetValue(Grid.RowProperty, gridRowIndex);
                        tbx.SetValue(Grid.ColumnProperty, 1);

                        //IValueConverter halfWidthConverter = new DoubleValueBy2Converter();
                        if (length != null && length.MaximumLength > 150)
                            tbx.SetValue(Grid.ColumnSpanProperty, 2);

                        //Binding widthBinding = new Binding { Path = new PropertyPath("ActualWidth"), ElementName = "col1", Converter = halfWidthConverter };
                        //tbx.SetBinding(TextBox.WidthProperty, widthBinding);
                        gridRowIndex++;
                    }
                    else if (pi.PropertyType == typeof(bool))
                    {
                        var chk = new CheckBox();
                        var tb = new TextBlock();
                        //var grid = new Grid();
                        //grid.Width = 300;
                        //grid.Height = 26;
                        //grid.Children.Add(tb);
                        //grid.Children.Add(tbx);
                        chk.IsEnabled = false;
                        chk.Padding = new Thickness(0);
                        chk.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                        chk.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                        chk.Margin = new Thickness(5, 0, 2, 0);
                        tb.Width = 150;

                        tb.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                        tb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                        Binding binding = new Binding { Path = new PropertyPath(pi.Name), Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.Explicit };

                        if (display != null)
                            tb.Text = display.Name;
                        else
                            tb.Text = pi.Name;
                        if (readOnly != null)
                        {
                            //chk.IsEnabled = !readOnly.IsReadOnly;
                            chk.Tag = readOnly.IsReadOnly;
                        }
                        chk.SetBinding(CheckBox.IsCheckedProperty, binding);
                        gridEditElements.RowDefinitions.Add(new RowDefinition { Height = new GridLength(25) });
                        gridEditElements.Children.Add(tb);
                        gridEditElements.Children.Add(chk);
                        tb.SetValue(Grid.RowProperty, gridRowIndex);
                        chk.SetValue(Grid.RowProperty, gridRowIndex);
                        chk.SetValue(Grid.ColumnProperty, 1);
                        gridRowIndex++;
                    }
                }
            }
        }

        private void GoToEditState()
        {
            foreach (var elm in gridEditElements.Children)
            {
                if (elm is TextBox)
                {
                    var tbx = elm as TextBox;
                    tbx.IsReadOnly = tbx.Tag == null ? false : (bool)tbx.Tag;
                }
                else if (elm is CheckBox)
                {
                    var chk = elm as CheckBox;
                    chk.IsEnabled = chk.Tag == null ? true : (bool)chk.Tag;
                }
            }
        }

        private void GoToViewState(bool updateSource = false)
        {
            foreach (var elm in gridEditElements.Children)
            {
                if (elm is TextBox)
                {
                    var tbx = elm as TextBox;
                    if (updateSource && !(tbx.Tag == null ? false : (bool)tbx.Tag))
                    {
                        var bindingEx = tbx.GetBindingExpression(TextBox.TextProperty);
                        bindingEx.UpdateSource();
                    }
                    tbx.IsReadOnly = true;
                }
                else if (elm is CheckBox)
                {
                    var chk = elm as CheckBox;
                    if (updateSource && !(chk.Tag == null ? false : (bool)chk.Tag))
                    {
                        var bindingEx = chk.GetBindingExpression(CheckBox.IsCheckedProperty);
                        bindingEx.UpdateSource();
                    }
                    chk.IsEnabled = false;
                }
            }
        }

        private long CalculateAddedItemID(RadTreeViewItem parentNode,out long parentId)
        {
            //var parentNode = parentNode.Parent as RadTreeViewItem;
            long parentSectionId = -1;
            parentId = parentSectionId;
            long lastItemId = 0;
            int m=1000;
            if (parentNode != null)
            {
                var realPID = (long)parentNode.Tag.GetPropertyValue(IDPropertyName);
                parentSectionId = Math.Abs(realPID);
                if (parentSectionId == 1)
                    m = 100;
                parentId = realPID;
                var childNodes = GetChildItems(parentNode);
                if (childNodes.Count() > 0)
                    lastItemId = childNodes.Max(p => Math.Abs((long)p.GetPropertyValue(IDPropertyName)));
                if (lastItemId == 0)
                    return -(parentSectionId * m + lastItemId + 1);
                else
                    return -(lastItemId + 1);
            }
            else
                return -1;
        }

        private IEnumerable<object> GetChildItems(RadTreeViewItem node)
        {
             return node.Items.Select(p => ((RadTreeViewItem)p).Tag);          
        }

        private void OnAddNodeCommand()
        {
            Mode = TreeViewMode.New;
            if (AutoGenerateFields)
                GoToEditState();
            else
            {
                cp1.Content = EditItemsTemplate.LoadContent();
            }
            _isFirstAddedNodeSelected = true;
            var newEntity = Activator.CreateInstance(_entityType);
            long parentId =-1;
            long id =-1;
            if (AutoGenerateFields && SelectedItem != null || SelectedItemCopy != null)
                id = CalculateAddedItemID(radTreeView1.SelectedItem as RadTreeViewItem,out parentId);
            //if (System.Convert.ToInt64(parentId) < -1)
            //    newEntity.GetType().GetProperty(IDPropertyName).SetValue(newEntity, System.Convert.ToInt16(parentId) - 1, null);
            //else
                newEntity.GetType().GetProperty(IDPropertyName).SetValue(newEntity, id, null);
            newEntity.GetType().GetProperty(ParentIdPropertyName).SetValue(newEntity, parentId, null);
            newEntity.GetType().GetProperty(NamePropertyName).SetValue(newEntity, "نام را وارد کنید...", null);
            
            newEntity.GetType().GetProperty(IsActivePropertyName).SetValue(newEntity, true, null);
            IList list = ItemsSource as IList;
            list.Add(newEntity);
            radTreeView1.IsEnabled = false;
        }

        private void OnDeleteNodeCommand()
        {
            IList col = ItemsSource as IList;
            if (!string.IsNullOrEmpty(DeleteDatePropertyName))
                SelectedItem.GetType().GetProperty(DeleteDatePropertyName).SetValue(SelectedItem, DateTime.Now, null);
            col.Remove(SelectedItem);
            
            SelectedItem = null;
        }

        private void OnEditNodeCommand()
        {
            Mode = TreeViewMode.Edit;
            if (AutoGenerateFields)
                GoToEditState();
            else
            {
                cp1.Content = EditItemsTemplate.LoadContent();
                SelectedItemCopy = SelectedItem.Clone();
            }
        }

        private void OnCancelCommand()
        {
            radTreeView1.IsEnabled = true;
            
            if (Mode == TreeViewMode.New)
            {
                
                if (TmpAddedNodes != null && TmpAddedNodes.Count > 0)
                {
                    IList col = ItemsSource as IList;
                    col.Remove(TmpAddedNodes[0].Tag);
                }
            }
            else
            {
                radTreeView1.SelectedItem = null;      
                
            }
            SelectedItem = null;
            SelectedItemCopy = null;
            if (AutoGenerateFields)
                GoToViewState();
            else
                cp1.Content = ItemsTemplate.LoadContent();
            Mode = TreeViewMode.View;
        }

        private void OnCommitChangesCommand()
        {
            if (Mode == TreeViewMode.New && UserAddedNodes != null)
            {
                UserAddedNodes.Add(SelectedItem);
            }
            else if (Mode == TreeViewMode.Edit && UserEditedNodes != null)
            {
                if (AutoGenerateFields && SelectedItem.GetDecimalValue(IDPropertyName) > 0)
                {
                    if (!UserEditedNodes.Contains(SelectedItem))
                        UserEditedNodes.Add(SelectedItem);
                }
                else if (!AutoGenerateFields && SelectedItemCopy.GetDecimalValue(IDPropertyName) > 0)
                {
                    if (!UserEditedNodes.Contains(SelectedItemCopy))
                        UserEditedNodes.Add(SelectedItemCopy);
                }
            }
            if (!string.IsNullOrEmpty(ModifyDatePropertyName))
            {
                if (AutoGenerateFields)
                    SelectedItem.GetType().GetProperty(ModifyDatePropertyName).SetValue(SelectedItem, DateTime.Now, null);
                else
                    SelectedItemCopy.GetType().GetProperty(ModifyDatePropertyName).SetValue(SelectedItemCopy, DateTime.Now, null);
            }
            radTreeView1.IsEnabled = true;
            if (AutoGenerateFields)
                GoToViewState(true);
            else
            {
                ((RadTreeViewItem)radTreeView1.SelectedItem).Tag = SelectedItemCopy;
                cp1.Content = ItemsTemplate.LoadContent();
            }
            Mode = TreeViewMode.View;

        }

        void radTreeView1_Selected(object sender, Telerik.Windows.RadRoutedEventArgs e)
        {
            //foreach (var cntrl in gridEditElements.Children)
            //{
            //    if (cntrl is TextBox)
            //    {
            //        var tbx = cntrl as TextBox;
            //        var binding = tbx.GetBindingExpression(TextBox.TextProperty);
            //        binding.UpdateSource();
            //    }
            //}
            SelectedItem = (Entity)((RadTreeViewItem)radTreeView1.SelectedItem).Tag;
            if (!AutoGenerateFields)
            {
                if (Mode == TreeViewMode.View)
                    SelectedItemCopy = (Entity)((RadTreeViewItem)radTreeView1.SelectedItem).Tag;
                else
                    SelectedItemCopy = (Entity)((RadTreeViewItem)radTreeView1.SelectedItem).Tag.Clone();
            }
        }

        //public event NotifyCollectionChangedEventHandler ItemsSourcesCollectionChangedHandler
        //{
        //    add {if() ((INotifyCollectionChanged)ItemsSource).CollectionChanged += value; }
        //    remove { ((INotifyCollectionChanged)ItemsSource).CollectionChanged -= value; }
        //}


        public void BuildTreeView(bool rebuild = false)
        {
            if (ItemsSource != null)
            {
                SelectedItem = null;
                var genericItems = ItemsSource.Cast<Entity>();
                if (rebuild)
                    TVItems.Clear();
                if (ItemsSource is INotifyCollectionChanged && !_isMainCollectionChangedRegistered)
                {
                    ((INotifyCollectionChanged)ItemsSource).CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ocItems_CollectionChanged);
                }
                TVItems = _bsBuilder.BuildTreeView(genericItems,
                    IDPropertyName, NamePropertyName, ParentIdPropertyName, IsExpandedPropertyName, IsActivePropertyName,
                    NodeMode);
                RefreshCommands();
                if (!_isMainCollectionChangedRegistered)
                    TVItems.CollectionChanged += new NotifyCollectionChangedEventHandler(TVItems_CollectionChanged);
                _isMainCollectionChangedRegistered = true;
            }
        }

        void TVItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            ((RelayCommand)AddNode).RaiseCanExecuteChanged();
        }
        public delegate void RemoveItems(IList col, List<Entity> removedItems);
        void ocItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //TVItems = _bsBuilder.BuildTreeView(sender as IEnumerable<Entity>,
            //    IDPropertyName, NamePropertyName, ParentIdPropertyName, IsExpandedPropertyName, IsActivePropertyName,
            //    NodeMode);
            if (!_isChildRemoving)
            {
                List<Entity> removedItems = null;
                if (e.NewItems != null)
                {
                    TmpAddedNodes = _bsBuilder.AddItemsToTreeView(TVItems, sender as IEnumerable<Entity>, e.NewItems.Cast<Entity>());
                    if (_isFirstAddedNodeSelected && TmpAddedNodes != null && TmpAddedNodes.Count > 0)
                    {
                        var parentNode = TmpAddedNodes[0].Parent as RadTreeViewItem;
                        if (parentNode != null)
                        {
                            
                            parentNode.IsExpanded = true;
                        }
                        //radTreeView1.SelectedItem = AddedNodes[0];
                        
                        
                        TmpAddedNodes[0].IsSelected = true;
                        TmpAddedNodes[0].Focus();
                        if (AutoGenerateFields)
                            SelectedItem = TmpAddedNodes[0].Tag;
                        else
                            SelectedItemCopy = TmpAddedNodes[0].Tag;
                       // radTreeView1.UpdateLayout();
                    }
                }
                else if (e.OldItems != null)
                {
                    removedItems = _bsBuilder.RemoveItemsFromTreeView(TVItems, sender as IList, e.OldItems.Cast<Entity>());

                    Dispatcher.BeginInvoke(_removeItems, new object[] { sender as IList, removedItems });
                }
            }
        }

        void  RemoveChildItems(IList col,List<Entity> removedItems)
        {
            _isChildRemoving = true;
            foreach (var item in removedItems)
            {
                col.Remove(item);
            }
            _isChildRemoving = false;
            UpdateUserAddedOrRemovedItems(removedItems);
        }

        private void UpdateUserAddedOrRemovedItems(List<Entity> removedItems)
        {
            //_isUserRemoveCommand = false;
            foreach (var item in removedItems)
            {
                if ((long)item.GetPropertyValue(IDPropertyName) > 0 && UserRemovedNodes != null)
                    UserRemovedNodes.Add(item);
                var toRemoveItem = UserAddedNodes.Contains(item) ? item : null;//Removing from additems if exists
                if (toRemoveItem != null && UserAddedNodes != null)
                    UserAddedNodes.Remove(toRemoveItem);
            }
        }

        private void RefreshCommands()
        {
            ((RelayCommand)AddNode).RaiseCanExecuteChanged();
            ((RelayCommand)DeleteNode).RaiseCanExecuteChanged();
            ((RelayCommand)EditNode).RaiseCanExecuteChanged();
            ((RelayCommand)Cancel).RaiseCanExecuteChanged();
            ((RelayCommand)CommitChanges).RaiseCanExecuteChanged();
        }

        private void radComboBox1_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
        {

        }

        #endregion

        
    }

    internal enum TreeViewMode
    {
        View,
        New,
        Edit
    }

    public class NodModeWrapper
    {

        public NodeMode NodeMode { get; set; }

        public string NodeModeName { get; set; }
        
    }
}
